package com.cencat.common.context;

import lombok.extern.slf4j.Slf4j;

/**
 * 租户上下文持有者
 * 用于在多线程环境中存储和获取租户上下文信息
 */
@Slf4j
public class TenantContextHolder {
    
    private static final ThreadLocal<TenantContext> CONTEXT_HOLDER = new ThreadLocal<>();
    
    private TenantContextHolder() {
        // 私有构造器，防止实例化
    }
    
    /**
     * 设置租户上下文
     * @param context 租户上下文
     */
    public static void setTenantContext(TenantContext context) {
        if (context == null) {
            clear();
            return;
        }
        
        if (log.isDebugEnabled()) {
            log.debug("设置租户上下文: {}", context.getSummary());
        }
        CONTEXT_HOLDER.set(context);
    }
    
    /**
     * 获取租户上下文
     * @return 租户上下文
     */
    public static TenantContext getTenantContext() {
        TenantContext context = CONTEXT_HOLDER.get();
        if (context == null && log.isDebugEnabled()) {
            log.debug("租户上下文为空");
        }
        return context;
    }
    
    /**
     * 获取当前租户ID
     * @return 租户ID
     */
    public static Long getCurrentTenantId() {
        TenantContext context = getTenantContext();
        return context != null ? context.getTenantId() : null;
    }
    
    /**
     * 获取当前租户编码
     * @return 租户编码
     */
    public static String getCurrentTenantCode() {
        TenantContext context = getTenantContext();
        return context != null ? context.getTenantCode() : null;
    }
    
    /**
     * 获取当前用户ID
     * @return 用户ID
     */
    public static Long getCurrentUserId() {
        TenantContext context = getTenantContext();
        return context != null ? context.getUserId() : null;
    }
    
    /**
     * 获取当前用户名
     * @return 用户名
     */
    public static String getCurrentUsername() {
        TenantContext context = getTenantContext();
        return context != null ? context.getUsername() : null;
    }
    
    /**
     * 判断当前租户上下文是否有效
     * @return 是否有效
     */
    public static boolean isValid() {
        TenantContext context = getTenantContext();
        return context != null && context.isValid();
    }
    
    /**
     * 判断当前租户是否启用
     * @return 是否启用
     */
    public static boolean isEnabled() {
        TenantContext context = getTenantContext();
        return context != null && context.isEnabled();
    }
    
    /**
     * 判断当前租户套餐是否过期
     * @return 是否过期
     */
    public static boolean isPackageExpired() {
        TenantContext context = getTenantContext();
        return context != null && context.isPackageExpired();
    }
    
    /**
     * 清理租户上下文
     */
    public static void clear() {
        TenantContext context = CONTEXT_HOLDER.get();
        if (context != null && log.isDebugEnabled()) {
            log.debug("清理租户上下文: {}", context.getSummary());
        }
        CONTEXT_HOLDER.remove();
    }
    
    /**
     * 执行带租户上下文的任务
     * @param context 租户上下文
     * @param task 任务
     */
    public static void executeWithContext(TenantContext context, Runnable task) {
        if (context == null || task == null) {
            return;
        }
        
        TenantContext oldContext = getTenantContext();
        try {
            setTenantContext(context);
            task.run();
        } finally {
            if (oldContext != null) {
                setTenantContext(oldContext);
            } else {
                clear();
            }
        }
    }
    
    /**
     * 执行带租户上下文的任务并返回结果
     * @param context 租户上下文
     * @param task 任务
     * @return 任务结果
     */
    public static <T> T executeWithContext(TenantContext context, Supplier<T> task) {
        if (context == null || task == null) {
            return null;
        }
        
        TenantContext oldContext = getTenantContext();
        try {
            setTenantContext(context);
            return task.get();
        } finally {
            if (oldContext != null) {
                setTenantContext(oldContext);
            } else {
                clear();
            }
        }
    }
    
    /**
     * 函数式接口
     */
    @FunctionalInterface
    public interface Supplier<T> {
        T get();
    }
}